package cn.kgc.config;

import cn.kgc.util.BaseException;
import cn.kgc.util.Result;
import cn.kgc.util.ResultConstant;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

/**
 * 捕获控制器中的异常信息将异常信息封装成Result对象将Result对象返回给前端。
 * @author wangyue
 * @version 1.0
 */
@ControllerAdvice(value = "cn.kgc.controller")
@SuppressWarnings("all")
public class ExceptionAdvice {

    @ExceptionHandler(value = ConstraintViolationException.class)
    public ResponseEntity<Result<Object>> handleConstraintException(ConstraintViolationException e){
        //获得参数验证的异常信息
        Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
        //将异常信息封装到errorMap中(key字段名 value是错误信息)
        HashMap<String, String> errorMap = new HashMap<>();
        //遍历所有的错误信息
        //selectOne.id:  角色编码最小值是1
        for (ConstraintViolation<?> constraintViolation : constraintViolations) {
            //selectOne.id ==>  ["selectOne","id"] ==> id
           String fieldName=
                   constraintViolation.getPropertyPath().toString().split("\\.")[1];
            //trim()方法去掉字符串作用的空格
           String fieldError=constraintViolation.getMessage().trim();
           errorMap.put(fieldName,fieldError);
        }
        return getResponseEntity(Result.error(errorMap));
    }

    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public ResponseEntity<Result<Object>> handleMethodValidException(MethodArgumentNotValidException e){
         //获得参数验证的错误信息
         BindingResult bindingResult = e.getBindingResult();
         List<FieldError> fieldErrors = bindingResult.getFieldErrors();
         //将错误信息封装到errorMap中(key字段名 value是错误信息)
         HashMap<String, String> errorMap = new HashMap<>();
         //遍历所有的错误信息
         for (FieldError fieldError : fieldErrors) {
             //将错误信息封装到errorMap中
             errorMap.put(fieldError.getField(),fieldError.getDefaultMessage());
         }
         //将errorMap封装到Result对象中,将Result对象放入到响应体中
         return getResponseEntity(Result.error(errorMap));
    }

    /**
     * 捕获控制器中的BaseException异常信息,将异常信息封装到Result对象中,并且将Result对象放入到响应实体中
     */
    @ExceptionHandler(value = BaseException.class)
    public ResponseEntity<Result<Object>> handleBaseException(BaseException baseException){
        //将错误信息封装到Result对象中将Result对象放入到响应实体中
        return getResponseEntity(Result.error(baseException));
    }

    /**
     * 捕获Java中的异常信息,将异常信息封装到Result对象中,并且将Result对象放入到响应实体中
     */
    @ExceptionHandler(value = Exception.class)
    public ResponseEntity<Result<Object>> handleException(Exception exception){
        Result<Object> result= Result.error(
                ResultConstant.ERROR.getCode(),ResultConstant.ERROR.getMsg()
        );
        return getResponseEntity(result);
    }

    /**
     * 将Result对象放入到响应实体中
     */
    private ResponseEntity<Result<Object>> getResponseEntity(Result<Object> result){
        //在响应头中添加返回数据的类型是JSON格式的字符串
        HttpHeaders httpHeaders=new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
        return new ResponseEntity<>(result,httpHeaders ,HttpStatus.OK);
    }
}
